package sk.stuba.fiit.pki.dao.impl;

import java.math.BigInteger;
import java.util.List;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import sk.stuba.fiit.pki.dao.SerialDao;
import sk.stuba.fiit.pki.entity.SerialSeqEntity;
import sk.stuba.fiit.pki.service.SerialService;

@Repository("serialDao")
@Transactional(readOnly = true)
public class SerialDaoImpl implements SerialDao {
	
	@Autowired
	protected SessionFactory sessionFactory = null;

	public BigInteger allocateCRLSerialNumber() {
		Session session = sessionFactory.openSession();
		Transaction transaction = session.beginTransaction();
		SerialSeqEntity crlSeq;
		List<SerialSeqEntity> crlsSeq = (List<SerialSeqEntity>) session.createCriteria(SerialSeqEntity.class).add( Restrictions.like("name",SerialService.CRL_SEQ_NAME)).list();
		if(crlsSeq.size()==0){
			crlSeq = new SerialSeqEntity();
			crlSeq.setName(SerialService.CRL_SEQ_NAME);
			crlSeq.setSeq(new BigInteger("1"));
			session.saveOrUpdate(crlSeq);
		}else{
			crlSeq = crlsSeq.get(0);
			crlSeq.setSeq(crlSeq.getSeq().add(SerialService.CRL_SEQ_VAL));
			session.saveOrUpdate(crlSeq);
		}
		transaction.commit();
		session.close();
		return crlSeq.getSeq();
	}

	public BigInteger allocateCertSerialNumber() {
		Session session = sessionFactory.openSession();
		Transaction transaction = session.beginTransaction();
		SerialSeqEntity certSeq;
		List<SerialSeqEntity> certsSeq = (List<SerialSeqEntity>) session.createCriteria(SerialSeqEntity.class).add( Restrictions.like("name",SerialService.CERT_SEQ_NAME)).list();
		if(certsSeq.size()==0){
			certSeq = new SerialSeqEntity();
			certSeq.setName(SerialService.CERT_SEQ_NAME);
			certSeq.setSeq(new BigInteger("1"));
			session.saveOrUpdate(certSeq);
		}else{
			certSeq = certsSeq.get(0);
			certSeq.setSeq(certSeq.getSeq().add(SerialService.CERT_SEQ_VAL));
			session.saveOrUpdate(certSeq);
		}
		transaction.commit();
		session.close();
		return certSeq.getSeq();
	}

	public BigInteger allocateTimeStampSerialNumber() {
		Session session = sessionFactory.openSession();
		Transaction transaction = session.beginTransaction();
		SerialSeqEntity tsSeq;
		List<SerialSeqEntity> tssSeq = (List<SerialSeqEntity>) session.createCriteria(SerialSeqEntity.class).add( Restrictions.like("name",SerialService.TS_SEQ_NAME)).list();
		if(tssSeq.size()==0){
			tsSeq = new SerialSeqEntity();
			tsSeq.setName(SerialService.TS_SEQ_NAME);
			tsSeq.setSeq(new BigInteger("1"));
			session.saveOrUpdate(tsSeq);
		}else{
			tsSeq = tssSeq.get(0);
			tsSeq.setSeq(tsSeq.getSeq().add(SerialService.TS_SEQ_VAL));
			session.saveOrUpdate(tsSeq);
		}
		transaction.commit();
		session.close();
		return tsSeq.getSeq();
	}

	public BigInteger allocateOcspSerialNumber() {
		Session session = sessionFactory.openSession();
		Transaction transaction = session.beginTransaction();
		SerialSeqEntity ocspSeq;
		List<SerialSeqEntity> ocspsSeq = (List<SerialSeqEntity>) session.createCriteria(SerialSeqEntity.class).add( Restrictions.like("name",SerialService.OCSP_SEQ_NAME)).list();
		if(ocspsSeq.size()==0){
			ocspSeq = new SerialSeqEntity();
			ocspSeq.setName(SerialService.OCSP_SEQ_NAME);
			ocspSeq.setSeq(new BigInteger("1"));
			session.saveOrUpdate(ocspSeq);
		}else{
			ocspSeq = ocspsSeq.get(0);
			ocspSeq.setSeq(ocspSeq.getSeq().add(SerialService.OCSP_SEQ_VAL));
			session.saveOrUpdate(ocspSeq);
		}
		transaction.commit();
		session.close();
		return ocspSeq.getSeq();
	}

	public void dealocateSerialNumber() {
		Session session = sessionFactory.openSession();
		Transaction transaction = session.beginTransaction();
		
		SerialSeqEntity seq;
		List<SerialSeqEntity> ocspsSeq = (List<SerialSeqEntity>) session.createCriteria(SerialSeqEntity.class).add( Restrictions.like("name",SerialService.OCSP_SEQ_NAME)).list();
		if(ocspsSeq.size()==0){
			seq = new SerialSeqEntity();
			seq.setName(SerialService.OCSP_SEQ_NAME);
			seq.setSeq(new BigInteger("1"));
			session.saveOrUpdate(seq);
		}else{
			seq = ocspsSeq.get(0);
			seq.setSeq(new BigInteger("1"));
			session.saveOrUpdate(seq);
		}
		List<SerialSeqEntity> tssSeq = (List<SerialSeqEntity>) session.createCriteria(SerialSeqEntity.class).add( Restrictions.like("name",SerialService.TS_SEQ_NAME)).list();
		if(tssSeq.size()==0){
			seq = new SerialSeqEntity();
			seq.setName(SerialService.TS_SEQ_NAME);
			seq.setSeq(new BigInteger("1"));
			session.saveOrUpdate(seq);
		}else{
			seq = tssSeq.get(0);
			seq.setSeq(new BigInteger("1"));
			session.saveOrUpdate(seq);
		}
		List<SerialSeqEntity> crlsSeq = (List<SerialSeqEntity>) session.createCriteria(SerialSeqEntity.class).add( Restrictions.like("name",SerialService.CRL_SEQ_NAME)).list();
		if(crlsSeq.size()==0){
			seq = new SerialSeqEntity();
			seq.setName(SerialService.CRL_SEQ_NAME);
			seq.setSeq(new BigInteger("1"));
			session.saveOrUpdate(seq);
		}else{
			seq = crlsSeq.get(0);
			seq.setSeq(new BigInteger("1"));
			session.saveOrUpdate(seq);
		}
		List<SerialSeqEntity> certsSeq = (List<SerialSeqEntity>) session.createCriteria(SerialSeqEntity.class).add( Restrictions.like("name",SerialService.CERT_SEQ_NAME)).list();
		if(certsSeq.size()==0){
			seq = new SerialSeqEntity();
			seq.setName(SerialService.CERT_SEQ_NAME);
			seq.setSeq(new BigInteger("1"));
			session.saveOrUpdate(seq);
		}else{
			seq = certsSeq.get(0);
			seq.setSeq(new BigInteger("1"));
			session.saveOrUpdate(seq);
		}	
		transaction.commit();
		session.close();	
	}

}
